package com.jt.www.admin.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.jt.www.admin.pay.service.PayCertService;
import com.jt.www.dao.mapper.issue.mapper.IssueListenerEntityMapper;
import com.jt.www.dao.mapper.issue.mapper.IssuePolicyLogEntityMapper;
import com.jt.www.dao.mapper.issue.mapper.IssueRecordEntityMapper;
import com.jt.www.dao.mapper.issue.mapper.MqMessageEntityMapper;
import com.jt.www.domain.enums.common.YesOrNoEnum;
import com.jt.www.enums.ResultEnum;
import com.jt.www.enums.issue.AppStatusEnum;
import com.jt.www.enums.issue.IssueEnum;
import com.jt.www.enums.issue.PolicyOrinvoiceSendStatusEnum;
import com.jt.www.exception.BizException;
import com.jt.www.exception.ServiceException;
import com.jt.www.model.issue.RepushQo;
import com.jt.www.model.issue.entity.IssueListenEntity;
import com.jt.www.model.issue.entity.IssuePolicyLogEntity;
import com.jt.www.model.issue.entity.IssueRecordEntity;
import com.jt.www.model.issue.entity.MqMessageEntity;
import com.jt.www.model.param.endorse.AppDetailProParam;
import com.jt.www.model.pay.ResBindQo;
import com.jt.www.model.pay.StatusRecordForOrderVO;
import com.jt.www.model.pay.StatusRecordVO;
import com.jt.www.model.pay.vo.PayCertVO;
import com.jt.www.model.remote.ins.CommonApplicationFormVo;
import com.jt.www.model.reps.GenericDataResponse;
import com.jt.www.model.reps.GenericListResponse;
import com.jt.www.model.reps.ResponseData;
import com.jt.www.model.reps.ResultDTO;
import com.jt.www.model.vo.endorse.AppDetailProVo;
import com.jt.www.model.vo.sdCheck.InsuranceCompanyVO;
import com.jt.www.model.vo.sdCheck.InsuredForProVO;
import com.jt.www.queue.issue.ElecPolicyMsglistener;
import com.jt.www.remote.DexClient;
import com.jt.www.remote.ins.InsClient;
import com.jt.www.util.DateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.text.ParseException;
import java.util.*;

import static com.jt.www.enums.ErrorCode.SUCCESS_CODE_0000;
import static com.jt.www.enums.ErrorCode.SUCCESS_MSG;
import static com.jt.www.enums.issue.IssueEnum.*;
import static com.jt.www.enums.issue.PolicyEnum.*;

/**
 * @author admin_ltf
 * @create 2019-06-03 14:48
 */
@Service
public class PayCertServiceImpl implements PayCertService {

    public static final Logger log = LoggerFactory.getLogger(PayCertServiceImpl.class);
    //初始化红冲接口
    public final static String SXZ_REDRUSH_INVOICE = "202006121108510";
    public final static String XZ_REDRUSH_INVOICE = "202006121117550";
    public final static String SP_REDRUSH_INVOICE = "202006121125090";
    @Autowired
    InsClient insClient;
    @Autowired
    IssueListenerEntityMapper issueListenerEntityMapper;
    @Autowired
    MqMessageEntityMapper mqMessageEntityMapper;
    @Autowired
    IssuePolicyLogEntityMapper issuePolicyLogEntityMapper;
    @Autowired
    IssueRecordEntityMapper issueRecordEntityMapper;
    @Autowired
    ElecPolicyMsglistener elecPolicyMsglistener;
    @Autowired
    DexClient dexClient;


    public ResultDTO bindAndUpdateData(PayCertVO vo) throws Exception {
        try {
            ResBindQo resBindQo = vo.getResBindQo();
            List<StatusRecordVO> list = vo.getStatusRecordVOs();
            if (resBindQo == null || list == null || list.size() == 0) {
                return new ResultDTO(ResultEnum.PARAM_ERROR, "请求参数不能为空");
            }
            //先获取到传入的投保单原始状态
            String appStatus = list.get(0).getOriStatus();
            //根据投保单号查询其他订单号，然后反查所有投保单，并获取到状态，查看是否一致，一致已订单更新状态
            String orderCode = list.get(0).getOrderCode();
            ResponseEntity<GenericListResponse<CommonApplicationFormVo>> genericList = insClient.applicationForm("01", orderCode);
            List<CommonApplicationFormVo> commonApplicationFormVoList = genericList.getBody().getList();
            //查询出来所有投保单状态
            List statusList = new ArrayList();
            for (CommonApplicationFormVo commonApplicationFormVo : commonApplicationFormVoList) {
                String status = commonApplicationFormVo.getApplicationStatus();
                statusList.add(status);
            }
            //查询到所有状态都一致,进行修改
            if (determineWhetherItIsConsistent(statusList, appStatus) && statusList.size() > 1) {
                //循环去绑定附件
                List codeList = new ArrayList();
                for (CommonApplicationFormVo commonApplicationFormVo : commonApplicationFormVoList) {
                    String applicationFormCode = commonApplicationFormVo.getApplicationFormCode();
                    resBindQo.setApplicationFormCode(applicationFormCode);
                    log.info("根据订单绑定单证,转换参数为 {} ", JSON.toJSONString(resBindQo));
                    ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = insClient.bindResources(resBindQo);
                    GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
                    String code = body.getCode();
                    log.info(DateUtils.getCurrentTime() + "绑定资源信息结果码" + code + ":" + body.getMsg());
                    codeList.add(code);
                }
                if (judgeCode(codeList, "0000")) {
                    //组装ins需要的报文，因前端未传值
                    StatusRecordForOrderVO statusRecordForOrderVO = new StatusRecordForOrderVO();
                    statusRecordForOrderVO.setCreateDate(new Date());
                    statusRecordForOrderVO.setNewStatus(vo.getStatusRecordVOs().get(0).getNewStatus());
                    statusRecordForOrderVO.setOperator(vo.getStatusRecordVOs().get(0).getOperator());
                    statusRecordForOrderVO.setOrderCode(orderCode);
                    statusRecordForOrderVO.setOriStatus(appStatus);
                    statusRecordForOrderVO.setRemarks(vo.getStatusRecordVOs().get(0).getRemarks());
                    statusRecordForOrderVO.setType(vo.getStatusRecordVOs().get(0).getType());
                    List<StatusRecordForOrderVO> statusRecordForOrderVOS = new ArrayList<>();
                    statusRecordForOrderVOS.add(statusRecordForOrderVO);
                    log.info("根据订单修改状态,转换参数为 {} ", JSON.toJSONString(statusRecordForOrderVOS));
                    ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity1 = insClient.updateApplicationStatusByOrder(statusRecordForOrderVOS);
                    GenericListResponse<Map<String, String>> genericListBody = genericListResponseResponseEntity1.getBody();
                    String genericListCode = genericListBody.getCode();
                    if ("0000".equals(genericListCode)) {
                        return new ResultDTO(ResultEnum.SUCCESS, "绑定成功");
                    } else {
                        return new ResultDTO(ResultEnum.SERVER_ERROR, "绑定失败");
                    }
                }
            } else {
                ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = insClient.bindResources(resBindQo);
                GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
                String code = body.getCode();
                log.info(DateUtils.getCurrentTime() + "绑定资源信息结果码" + code + ":" + body.getMsg());
                if ("0000".equals(code)) {
                    // 去修改状态
                    genericListResponseResponseEntity = insClient.updateApplicationStatus(list);
                    body = genericListResponseResponseEntity.getBody();
                    code = body.getCode();
                    log.info(DateUtils.getCurrentTime() + "绑定资源后修改投保单状态结果码" + code + ":" + body.getMsg());
                    if ("0000".equals(code)) {
                        return new ResultDTO(ResultEnum.SUCCESS, "成功");
                    } else {
                        return new ResultDTO(ResultEnum.SERVER_ERROR, "绑定失败");
                    }

                } else {
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "绑定失败");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResultDTO(ResultEnum.SERVER_ERROR, "绑定失败");
    }

    /**
     * 判断状态是否一致
     *
     * @param list
     * @return
     */
    public Boolean determineWhetherItIsConsistent(List list, String appStatus) {
        for (Object spid : list) {
            if (!spid.equals(appStatus)) {
                log.info("同一个订单下，所有投保单状态不一致");
                return false;
            }
        }
        return true;
    }

    /**
     * 判断状态是否一致
     *
     * @param list
     * @return
     */
    public Boolean judgeCode(List list, String code) {
        for (Object spid : list) {
            if (!spid.equals(code)) {
                log.info("同一个订单下，绑定code不一致");
                return false;
            }
        }
        return true;
    }

    public ResultDTO updateApplicationStatus(List<StatusRecordVO> statusRecordVOs) {
        try {
            if (statusRecordVOs == null || statusRecordVOs.size() == 0) {
                return new ResultDTO(ResultEnum.PARAM_ERROR, "请求参数不能为空");
            }
            //获取投保单号状态
            for (StatusRecordVO statusRecordVO : statusRecordVOs) {

                AppDetailProParam p = new AppDetailProParam();
                AppDetailProVo detailVos;
                ResponseEntity<GenericDataResponse<AppDetailProVo>> appDetailPro;
                p.setAppCode(statusRecordVO.getApplicationFormCode());
                p.setChannelCode("edu");    // 渠道编号
                p.setUserCode(statusRecordVO.getOperator());
                try {
                    appDetailPro = insClient.searchAppDetailPro(p);
                    detailVos = appDetailPro.getBody().getData();
                } catch (Exception e) {
                    log.info("查询投保单信息失败{}", statusRecordVO.getApplicationFormCode());
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "投保单状态更新失败");
                }

                if (!statusRecordVO.getOriStatus().equals(detailVos.getApplicationStatus())) {
                    log.info("投保单状态已改变 投保单号：{}，投保单当前状态：{}，接口入参原始状态：{}",
                            statusRecordVO.getApplicationFormCode(), detailVos.getApplicationStatus(), statusRecordVO.getOriStatus());
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "投保单状态已改变 投保单号：" + statusRecordVO.getApplicationFormCode()
                            + "，投保单当前状态：" + detailVos.getApplicationStatus()
                            + "，接口入参原始状态：" + statusRecordVO.getOriStatus());
                }

                String newStatus = statusRecordVO.getNewStatus();
                if (AppStatusEnum.AS_22.getCode().equals(newStatus)) {
                    //查询大平台是否已出单
                    if (AppStatusEnum.AS_10.getCode().equals(detailVos.getApplicationStatus()) || AppStatusEnum.AS_21.getCode().equals(detailVos.getApplicationStatus())) {
                        return new ResultDTO(ResultEnum.SERVER_ERROR, "投保单状态更新失败");
                    }
                }
            }

            String orderCode = statusRecordVOs.get(0).getOrderCode();
            if (StringUtils.isEmpty(orderCode)) {
                return new ResultDTO(ResultEnum.PARAM_ERROR, "订单号不能为空");
            }
            String appStatus = statusRecordVOs.get(0).getOriStatus();
            //根据投保单号查询其他订单号，然后反查所有投保单，并获取到状态，查看是否一致，一致已订单更新状态
            ResponseEntity<GenericListResponse<CommonApplicationFormVo>> genericList = insClient.applicationForm("01", orderCode);
            List<CommonApplicationFormVo> commonApplicationFormVoList = genericList.getBody().getList();
            //查询出来所有投保单状态
            List statusList = new ArrayList();
            for (CommonApplicationFormVo commonApplicationFormVo : commonApplicationFormVoList) {
                String status = commonApplicationFormVo.getApplicationStatus();
                statusList.add(status);
            }
            if (determineWhetherItIsConsistent(statusList, appStatus) && statusList.size() > 1) {
                List statusCodeList = new ArrayList();
                for (CommonApplicationFormVo commonApplicationFormVo : commonApplicationFormVoList) {
                    statusRecordVOs.get(0).setApplicationFormCode(commonApplicationFormVo.getApplicationFormCode());
                    //根据传入的投保单号查询到订单
                    ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = insClient.updateApplicationStatus(statusRecordVOs);
                    GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
                    String code = body.getCode();
                    if ("0000".equals(code)) {
                        log.info("投保单号: {} ,状态更新成功", commonApplicationFormVo.getApplicationFormCode());
                    } else {
                        log.info("投保单号: {} ,状态更新失败", commonApplicationFormVo.getApplicationFormCode());
                    }
                    statusCodeList.add(code);
                }
                //判断状态是否一致，一致成功返回
                if (determineWhetherItIsConsistent(statusCodeList, SUCCESS_CODE_0000)) {
                    return new ResultDTO(ResultEnum.SUCCESS_0000, "投保单状态更新成功");
                } else {
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "投保单状态更新失败");
                }

            } else {
                //根据传入的投保单号查询到订单
                ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = insClient.updateApplicationStatus(statusRecordVOs);
                GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
                String code = body.getCode();
                if ("0000".equals(code)) {
                    return new ResultDTO(ResultEnum.SUCCESS_0000, "投保单状态更新成功");
                } else {
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "投保单状态更新失败");
                }
            }

            /*ResponseEntity<GenericListResponse<Map<String, String>>> genericListResponseResponseEntity = insClient.updateApplicationStatus(statusRecordVOs);
            GenericListResponse<Map<String, String>> body = genericListResponseResponseEntity.getBody();
            String code = body.getCode();
            if ("0000".equals(code)) {
                return new ResultDTO(ResultEnum.SUCCESS_0000, "投保单状态更新成功");
            } else {
                return new ResultDTO(ResultEnum.SERVER_ERROR, "投保单状态更新失败");
            }*/
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResultDTO(ResultEnum.SERVER_ERROR, "投保单状态更新失败");
    }

    /**
     * 报文重发
     *
     * @param repushQo
     * @return
     */
    public ResultDTO updateMessageStatus(RepushQo repushQo) {
        try {
            log.debug("issuelog/repush, 出单重推请求参数:{}", repushQo);
            String applicationFormCode = repushQo.getApplicationFormCode();
            //获取投保单号状态
            AppDetailProParam p = new AppDetailProParam();
            AppDetailProVo detailVos;
            ResponseEntity<GenericDataResponse<AppDetailProVo>> appDetailPro;
            p.setAppCode(applicationFormCode);
            p.setChannelCode("edu");    // 渠道编号
            p.setUserCode(repushQo.getOperator());
            try {
                appDetailPro = insClient.searchAppDetailPro(p);
                detailVos = appDetailPro.getBody().getData();
            } catch (Exception e) {
                log.info("查询投保单信息失败{}", applicationFormCode);
                return new ResultDTO(ResultEnum.SERVER_ERROR, "查询投保单状态失败");
            }
            if (AppStatusEnum.AS_10.getCode().equals(detailVos.getApplicationStatus())) {
                return new ResultDTO(ResultEnum.SERVER_ERROR, "该投保单已出单,请勿重复出单");
            }

            // 若状态为待出单,  10分钟之后才能进行重发
            if (AppStatusEnum.AS_22.getCode().equals(detailVos.getApplicationStatus())) {
                //查询数据库第一次出单发送时间
                List<IssueListenEntity> entities = getIssueListenEntities(repushQo);
                if (CollectionUtils.isNotEmpty(entities)) {
                    IssueListenEntity issueListenEntity = entities.get(0);
                    Date sendDate = issueListenEntity.getSendTime();
                    //60s之内不能进行第二次发送
                    Date afterDate = new Date(sendDate.getTime() + 1000 * 10 * 60);
                    if (afterDate.getTime() > System.currentTimeMillis()) {
                        return new ResultDTO(ResultEnum.SERVER_ERROR, "请在10分钟之后重试");
                    }
                }
                //获取到投保中心第一次发送报文时间
                ResponseData responseData = insClient.searchOrderDetailPro(applicationFormCode, repushQo.getCompanyCode());
                log.info("投保中心返回第一次出单发送时间为{}", JSON.toJSON(responseData));
                Date oneSendDate = DateUtils.strToDate((String) responseData.getData());
                //点击重发时间在报文发送过程中2分钟之内不允许重发
                Date afterSendDate = new Date(oneSendDate.getTime() + 1000 * 60);
                if (afterSendDate.getTime() > System.currentTimeMillis()) {
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "出单过程中请勿重复发送");
                }
            }
            //若状态为出单失败,60s之内不能再次重发
            if (AppStatusEnum.AS_09.getCode().equals(detailVos.getApplicationStatus())) {
                List<IssueListenEntity> entities = getIssueListenEntities(repushQo);
                if (CollectionUtils.isNotEmpty(entities)) {
                    IssueListenEntity issueListenEntity = entities.get(0);
                    Date sendDate = issueListenEntity.getSendTime();
                    //60s之内不能进行第二次发送
                    Date afterDate = new Date(sendDate.getTime() + 1000 * 60);
                    if (afterDate.getTime() > System.currentTimeMillis()) {
                        return new ResultDTO(ResultEnum.SERVER_ERROR, "60s之内不能再次重发报文");
                    }
                }
            }
            //调用投保中心发送报文
            try {
                insClient.repush(repushQo);
            } catch (Exception e) {
                log.info("重发报文失败,投保单号{}", applicationFormCode);
                return new ResultDTO(ResultEnum.SERVER_ERROR, "重发报文失败");
            }
            int count = insertIssueListen(repushQo, applicationFormCode);
            if (count < 1) {
                throw new ServiceException("新增报文重发记录失败！");
            }
            log.info("投保单号{} 重推成功", applicationFormCode);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResultDTO(ResultEnum.SUCCESS, "报文重发成功");
    }


    /**
     * 报文重发 针对跟单
     *
     * @param repushQo
     * @return
     */
    public ResultDTO updateBackMessageStatus(RepushQo repushQo) {
        try {
            log.debug("backIssuelog/repush, 跟单出单重推请求参数:{}", repushQo);
            String applicationFormCode = repushQo.getApplicationFormCode();
            //获取投保单号状态
            AppDetailProParam p = new AppDetailProParam();
            AppDetailProVo detailVos;
            ResponseEntity<GenericDataResponse<AppDetailProVo>> appDetailPro;
            p.setAppCode(applicationFormCode);
            p.setChannelCode("edu");    // 渠道编号
            p.setUserCode(repushQo.getOperator());
            try {
                appDetailPro = insClient.searchAppDetailPro(p);
                detailVos = appDetailPro.getBody().getData();
            } catch (Exception e) {
                log.info("查询投保单信息失败{}", applicationFormCode);
                return new ResultDTO(ResultEnum.SERVER_ERROR, "查询投保单状态失败");
            }
            //首先主承先得出单，然后发送跟单
            if (AppStatusEnum.AS_10.getCode().equals(detailVos.getApplicationStatus()) || AppStatusEnum.AS_21.getCode().equals(detailVos.getApplicationStatus())
                    || AppStatusEnum.AS_02.getCode().equals(detailVos.getApplicationStatus()) ||
                    AppStatusEnum.AS_03.getCode().equals(detailVos.getApplicationStatus())) {
                //查询跟单是否已经出单
                List<InsuranceCompanyVO> insuranceCompanyVOS = detailVos.getInsuranceCompanyVOS();
                for (InsuranceCompanyVO insuranceCompanyVO : insuranceCompanyVOS) {
                    if (repushQo.getCompanyCode().equals(insuranceCompanyVO.getCode())) {
                        String name = insuranceCompanyVO.getName();
                        String code = insuranceCompanyVO.getCode();
                        String backPolicyNo = insuranceCompanyVO.getBackPolicyNo();
                        if (StringUtils.isNotEmpty(backPolicyNo)) {
                            log.debug("投保单号 {} ，跟单公司编码 {} ，公司公司名称 {} ,已出单 ,不能重复发送", applicationFormCode, code, name);
                            return new ResultDTO(ResultEnum.SERVER_ERROR, "跟单已出单，不需要重复发送");
                        }
                    }
                }
            } else {
                return new ResultDTO(ResultEnum.SERVER_ERROR, "主承未出单，请先主承出单才能发送跟单");
            }
            //调用投保中心发送报文
            try {
                insClient.repush(repushQo);
            } catch (Exception e) {
                log.info("重推跟单报文失败,投保单号{}", applicationFormCode);
                return new ResultDTO(ResultEnum.SERVER_ERROR, "重发跟单报文失败");
            }
            log.info("投保单号{} 重推跟单成功", applicationFormCode);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResultDTO(ResultEnum.SUCCESS, "跟单报文重发成功");
    }


    /**
     * 添加投保单重发报文记录
     *
     * @param repushQo
     * @param applicationFormCode
     */
    private int insertIssueListen(RepushQo repushQo, String applicationFormCode) {
        IssueListenEntity issueListenEntity = new IssueListenEntity();
        issueListenEntity.setApplicationFormCode(applicationFormCode);
        String operator = repushQo.getOperator();
        issueListenEntity.setOperator(operator);
        issueListenEntity.setSendTime(new Date());
        //根据投保单号查询产品信息
        AppDetailProParam p = new AppDetailProParam();
        AppDetailProVo detailVos = null;
        ResponseEntity<GenericDataResponse<AppDetailProVo>> appDetailPro;
        p.setAppCode(applicationFormCode);
        p.setChannelCode("edu");    // 渠道编号
        p.setUserCode(repushQo.getOperator());
        try {
            appDetailPro = insClient.searchAppDetailPro(p);
            detailVos = appDetailPro.getBody().getData();
        } catch (Exception e) {
            log.error("查询投保单信息失败{}", applicationFormCode);
        }
        issueListenEntity.setProductName(detailVos.getProductName());
        issueListenEntity.setHolderName(detailVos.getHolder().getCorporation().getName());
        for (InsuredForProVO insuredForProVO : detailVos.getInsuredList()) {
            issueListenEntity.setInsuredName(insuredForProVO.getCorporation().getName());
        }
        issueListenEntity.setOperatorName(repushQo.getOperatorName());
        int count = issueListenerEntityMapper.insert(issueListenEntity);
        return count;
    }

    /**
     * 查询报文最后一次发送时间
     *
     * @param repushQo
     * @return
     */
    private List<IssueListenEntity> getIssueListenEntities(RepushQo repushQo) {
        Weekend<IssueListenEntity> weekend = new Weekend<>(IssueListenEntity.class);
        WeekendCriteria<IssueListenEntity, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(IssueListenEntity::getApplicationFormCode, repushQo.getApplicationFormCode());
        weekend.orderBy("id").desc();
        return issueListenerEntityMapper.selectByExample(weekend);
    }

    /**
     * 根据投保单号获取电子保单or电子发票列表
     */
    public List<IssuePolicyLogEntity> getPolicyOrInvoice(String appCode, String type) {
        Weekend<IssuePolicyLogEntity> weekend = Weekend.of(IssuePolicyLogEntity.class);
        WeekendCriteria<IssuePolicyLogEntity, Object> criteria = weekend.weekendCriteria();
        criteria.andEqualTo(IssuePolicyLogEntity::getApplicationFormCode, appCode);
        criteria.andEqualTo(IssuePolicyLogEntity::getType, type);
        return issuePolicyLogEntityMapper.selectByExample(weekend);
    }

    public IssueRecordEntity getIssueRecord(String appCode) {
        IssueRecordEntity issueRecordEntity = new IssueRecordEntity();
        issueRecordEntity.setApplicationFormCode(appCode);
        return issueRecordEntityMapper.selectOne(issueRecordEntity);
    }

    /**
     * 根据投保单号删除电子保单或者电子发票
     * 后续重新获取
     *
     * @param appCode
     * @return
     */
    public int deletePolicyOrInvoice(String appCode) {
        IssuePolicyLogEntity issuePolicyLogEntity = new IssuePolicyLogEntity();
        issuePolicyLogEntity.setApplicationFormCode(appCode);
        return issuePolicyLogEntityMapper.delete(issuePolicyLogEntity);
    }

    /**
     * 根据投保单号删除出单相关mq记录表
     *
     * @param appCode
     * @return
     */
    public int deleteIssuePolicyLog(String appCode) {
        IssueRecordEntity issueRecordEntity = new IssueRecordEntity();
        issueRecordEntity.setApplicationFormCode(appCode);
        return issueRecordEntityMapper.delete(issueRecordEntity);
    }


    /**
     * 根据投保单号获取到最大的消息队列
     *
     * @param appCode
     * @return
     */
    public MqMessageEntity getMqMessage(String appCode) {
        //根据投保单号查询到目前mq消息
        MqMessageEntity mqMessage = mqMessageEntityMapper.queryMaxMqMessage(appCode);
        return mqMessage;
    }

    /**
     * 根据投保单号获取到mqId
     *
     * @param appCode
     * @return
     */
    public String mqMessageEntity(String appCode) {
        MqMessageEntity mqMessageEntity = getMqMessage(appCode);
        if (mqMessageEntity == null) {
            throw new BizException("mq消息未进行保存,联系IT处理");
        }
        String mqId = String.valueOf(mqMessageEntity.getId());
        return mqId;
    }


    /**
     * 获取电子保单
     *
     * @param repushQo
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    public ResultDTO getPolicy(RepushQo repushQo) throws Exception {
        log.debug("getPolicy/repush, 重新获取电子保单请求参数:{}", repushQo);
        String appCode = repushQo.getApplicationFormCode();
        if (StringUtils.isEmpty(appCode)) {
            throw new BizException("投保单号不能为空");
        }
        IssuePolicyLogEntity issuePolicyLogEntity = new IssuePolicyLogEntity();
        //根据投保单号查询电子保单表数据
        List<IssuePolicyLogEntity> policyList = getPolicyOrInvoice(appCode, PolicyOrinvoiceSendStatusEnum.POLICY_TYPE);
        int policyLenth = policyList.size();
        if (policyLenth > 0) {
            //获取到保单fileId是否为空
            for (int i = 0; i < policyLenth; i++) {
                String epolictId = policyList.get(i).getEPolicyId();
                if (StringUtils.isNotBlank(epolictId)) {
                    throw new BizException("已有电子保单，请联系IT进行处理");
                }
                issuePolicyLogEntity.setApplicationFormCode(appCode);
                issuePolicyLogEntity.setTimes(PolicyOrinvoiceSendStatusEnum.SEND_TIMES);
                issuePolicyLogEntity.setType(PolicyOrinvoiceSendStatusEnum.POLICY_TYPE);
                issuePolicyLogEntity.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_01.getCode());
                issuePolicyLogEntity.setId(policyList.get(i).getId());
                issuePolicyLogEntity.setUpdateTime(DateUtils.getCurrentTime());
                String sendDate = policyList.get(i).getUpdateTime();
                Date sendNewDate = DateUtils.zoneToLocalTime(sendDate);
                Date afterDate = new Date(sendNewDate.getTime() + 1000 * 60);
                //60s之内不能进行第二次发送
                if (afterDate.getTime() > System.currentTimeMillis()) {
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "60s之内不能再次获取保单");
                }
                //修改发送状态重新发送
                int updateAmount = issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLogEntity);
                if (updateAmount == 1) {
                    return new ResultDTO(ResultEnum.SUCCESS, SUCCESS_MSG);
                }
            }
        }
        //根据投保单号查询到mq消息
        String mqId = mqMessageEntity(appCode);
        //先查询消息表里是否有数据
        //根据id删除t_issue_policy_log和t_issue_record数据并重新获取
        deleteIssuePolicyLog(appCode);
        //重新获取电子保单
        List<MqMessageEntity> list = mqMessageEntityMapper.selectByIds(mqId);
        for (MqMessageEntity mqMessage : list) {
            Document document = DocumentHelper.parseText(mqMessage.getMessage());
            try {
                elecPolicyMsglistener.processMqMessage(document.getRootElement(), mqMessage.getIfCode(), System.currentTimeMillis());
            } catch (Exception e) {
                log.error("id为 { }的消息重试失败", mqMessage.getId());
                e.printStackTrace();
            }
        }
        return new ResultDTO(ResultEnum.SUCCESS, SUCCESS_MSG);
    }

    /**
     * 获取电子发票
     *
     * @param RepushQo
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    public ResultDTO getInvoice(RepushQo RepushQo) throws Exception {
        log.debug("getInvoice/repush, 重新获取电子发票请求参数:{}", RepushQo);
        String appCode = RepushQo.getApplicationFormCode();
        if (StringUtils.isEmpty(appCode)) {
            throw new BizException("投保单号不能为空");
        }
        IssuePolicyLogEntity issuePolicyLog = new IssuePolicyLogEntity();
        String currentTime = DateUtils.getCurrentTime();
        //根据投保单号查询电子发票数据
        List<IssuePolicyLogEntity> issuePolicyLogEntities = getPolicyOrInvoice(appCode, PolicyOrinvoiceSendStatusEnum.INVOICE_TYPE);
        //只有阳光,云南支持电子发票
        List<IssuePolicyLogEntity> policyList = getPolicyOrInvoice(appCode, PolicyOrinvoiceSendStatusEnum.POLICY_TYPE);
        for (IssuePolicyLogEntity issuePolicyLogEntity : policyList) {
            String proCode = issuePolicyLogEntity.getProCode();
            if (!IssueEnum.addProCodeList().contains(proCode)) {
                return new ResultDTO(ResultEnum.SERVER_ERROR, "该投保单不支持电子发票");
            }
        }
        if (issuePolicyLogEntities.size() > 0) {
            for (IssuePolicyLogEntity issuePolicyLogEntity : issuePolicyLogEntities) {
                if (StringUtils.isNotBlank(issuePolicyLogEntity.getEInvoiceId())) {
                    throw new BizException("已有电子发票，请联系IT进行处理");
                }
                //修改状态重发,除云南险种之外
                issuePolicyLog.setApplicationFormCode(appCode);
                issuePolicyLog.setTimes(PolicyOrinvoiceSendStatusEnum.SEND_TIMES);
                //判断电子发票是没有生成参数还是下载失败
                if (issuePolicyLogEntity.getIfCode().equals(YG_SZ_POLICY.getIfCode())
                        || issuePolicyLogEntity.getIfCode().equals(YG_NEW_SZ_POLICY.getIfCode())
                        || issuePolicyLogEntity.getIfCode().equals(YG_SP_POLICY.getIfCode())) {
                    issuePolicyLog.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_06.getCode());
                } else {
                    if (issuePolicyLogEntity.getIfCode().equals(IssueEnum.CODE_2.getIfCode())) {
                        issuePolicyLog.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_07.getCode());
                    } else {
                        issuePolicyLog.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_06.getCode());
                    }
                }
                issuePolicyLog.setType(PolicyOrinvoiceSendStatusEnum.INVOICE_TYPE);
                issuePolicyLog.setCreateTime(currentTime);
                issuePolicyLog.setId(issuePolicyLogEntity.getId());
                issuePolicyLog.setIfCode(issuePolicyLogEntity.getIfCode());
                String sendDate = issuePolicyLogEntity.getUpdateTime();
                Date sendNewDate = DateUtils.zoneToLocalTime(sendDate);
                Date afterDate = new Date(sendNewDate.getTime() + 1000 * 60);
                //60s之内不能进行第二次发送
                if (afterDate.getTime() > System.currentTimeMillis()) {
                    return new ResultDTO(ResultEnum.SERVER_ERROR, "60s之内不能再次获取发票");
                }
                int updateAmount = issuePolicyLogEntityMapper.updateByPrimaryKeySelective(issuePolicyLog);
                if (updateAmount == 1) {
                    return new ResultDTO(ResultEnum.SUCCESS, SUCCESS_MSG);
                }
            }
        }
        deleteIssuePolicyLog(appCode);
        //因电子发票是在电子保单之后，需要删除电子保单重新下载
        deletePolicyOrInvoice(appCode);

        String mqId = mqMessageEntity(appCode);
        List<MqMessageEntity> list = mqMessageEntityMapper.selectByIds(mqId);
        for (MqMessageEntity mqMessage : list) {
            Document document = DocumentHelper.parseText(mqMessage.getMessage());
            try {
                elecPolicyMsglistener.processMqMessage(document.getRootElement(), mqMessage.getIfCode(), System.currentTimeMillis());
            } catch (Exception e) {
                log.error("id为 { }的消息重试失败", mqMessage.getId());
                e.printStackTrace();
            }
        }
        return new ResultDTO(ResultEnum.SUCCESS, SUCCESS_MSG);
    }


    /**
     * 根据投保单号选择不同的红冲接口
     *
     * @param responseEntity
     * @param appCode
     * @param seqNo
     * @param doc
     * @return
     * @throws Exception
     */
    public ResponseEntity<String> byAppCodeChoiceInterface(ResponseEntity<String> responseEntity, String appCode, String seqNo, Document doc) throws Exception {
        IssueRecordEntity issueRecordEntity = getIssueRecord(appCode);
        String proCode = issueRecordEntity.getProCode();
        if (proCode.equals(CODE_2.getProCode())) {
            responseEntity = dexClient.text("edu", XZ_REDRUSH_INVOICE, "1.0", seqNo, doc.asXML());
        }
        if (proCode.equals(CODE_24.getProCode()) || proCode.equals(CODE_25.getProCode())) {
            responseEntity = dexClient.text("edu", SXZ_REDRUSH_INVOICE, "1.0", seqNo, doc.asXML());
        }
        if (proCode.equals(CODE_26.getProCode())) {
            responseEntity = dexClient.text("edu", SP_REDRUSH_INVOICE, "1.0", seqNo, doc.asXML());
        }
        return responseEntity;
    }

    /**
     * 是否满足红冲
     *
     * @param issuePolicyLogEntity
     * @return
     */
    public Boolean isRedRush(IssuePolicyLogEntity issuePolicyLogEntity) {
        if (StringUtils.isEmpty(issuePolicyLogEntity.getEInvoiceId())) {
            throw new BizException("该投保单号没有生成发票,不能进行红冲");
        }
        return true;
    }

    /**
     * 时间范围内是否允许第二次发送
     *
     * @param issuePolicyLogEntity
     * @return
     * @throws ParseException
     */
    public Boolean isDateRedRush(IssuePolicyLogEntity issuePolicyLogEntity) throws ParseException {
        String sendDate = issuePolicyLogEntity.getUpdateTime();
        Date sendNewDate = DateUtils.zoneToLocalTime(sendDate);
        Date afterDate = new Date(sendNewDate.getTime() + 1000 * 60);
        //60s之内不能进行第二次发送
        if (afterDate.getTime() > System.currentTimeMillis()) {
            throw new BizException("60s之内不能再次红冲电子发票");
        }
        return true;
    }

    /*
     *  发票红冲 (yes红冲完重新开发票， no红冲完不进行开发票)
     * @Author xq.wu
     * @Date 16:00 2020/1/8
     * @Param [repushQo]
     * @return com.jt.www.model.reps.ResultDTO
     **/
    public ResultDTO redRushInvoice(RepushQo repushQo, String make) throws Exception {
        String appCode = repushQo.getApplicationFormCode();
        if (StringUtils.isEmpty(appCode) || StringUtils.isEmpty(make)) {
            throw new BizException("投保单号或者标识不能为空");
        }
        //根据投保单号查询电子发票表
        List<IssuePolicyLogEntity> issuePolicyLogEntities = getPolicyOrInvoice(appCode, PolicyOrinvoiceSendStatusEnum.INVOICE_TYPE);
        IssuePolicyLogEntity t = new IssuePolicyLogEntity();
        if (CollectionUtils.isEmpty(issuePolicyLogEntities)) {
            throw new BizException("该投保单号没有发票记录,不能进行红冲");
        }
        for (IssuePolicyLogEntity issuePolicyLogEntity : issuePolicyLogEntities) {
            t.setId(issuePolicyLogEntity.getId());
            //先进行校验可否红冲
            isRedRush(issuePolicyLogEntity);
            //时间范围内是否允许重发
            isDateRedRush(issuePolicyLogEntity);
            //组装红冲报文
            String policyNo = issuePolicyLogEntity.getPolicyNo();
            Document doc = DocumentHelper.createDocument();
            Element policylist = doc.addElement("POLICYLIST");
            Element POLICYINFO = policylist.addElement("POLICYINFO");
            POLICYINFO.addElement("POLICYNO").addText(policyNo);
            t.setApplicationFormCode(appCode);
            log.info(DateUtils.getCurrentTime() + "投保单号是" + appCode + "红冲发票开始，入参" + doc.asXML());
            String seqNo = Long.toString(Math.abs(new Random().nextLong()));
            ResponseEntity<String> responseEntity = null;
            responseEntity = byAppCodeChoiceInterface(responseEntity, appCode, seqNo, doc);
            if (responseEntity == null || responseEntity.getStatusCodeValue() != 200) {
                log.error(appCode + "红冲电子发票失败");
                t.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_05.getCode());
                issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
            } else {
                log.info(DateUtils.getCurrentTime() + "投保单号是" + appCode + "红冲发票结束，回参" + responseEntity.getStatusCodeValue() + "," + responseEntity.getBody());
                //获取到返回参数
                String ebody = responseEntity.getBody();
                doc = DocumentHelper.parseText(ebody);
                String value = doc.getRootElement().element("POLICY").attribute("RETURN").getValue();
                //红冲成功,修改发送次数和状态,清空fileId表, 后续自动扫描重新下载
                if ("true".equals(value)) {
                    if (make.equals(YesOrNoEnum.NO.getType())) {
                        t.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_08.getCode()); //状态为红冲
                    } else {
                        t.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_06.getCode());
                        //学责险状态设置为7才可以推送
                        if (issuePolicyLogEntity.getProCode().equals(CODE_2.getProCode())) {
                            t.setStatus(PolicyOrinvoiceSendStatusEnum.PISS_07.getCode());
                        }
                    }
                    t.setTimes(PolicyOrinvoiceSendStatusEnum.SEND_TIMES);
                    t.setType(PolicyOrinvoiceSendStatusEnum.INVOICE_TYPE);
                    t.setUpdateTime(DateUtils.getCurrentTime());
                    issuePolicyLogEntityMapper.updateByPrimaryKeySelective(t);
                } else {
                    throw new BizException("保险公司返回信息错误,请联系保险公司处理");
                }
            }
        }
        return new ResultDTO(ResultEnum.SUCCESS, SUCCESS_MSG);
    }
}
